﻿using System;
using Sunny.Core.Exception;

namespace Sunny.Core.DefinedData
{
    [System.Serializable]
    public struct SInteger : IComparable<SInteger>
    {
        private readonly int? _number;

        public SInteger(int? value)
        {
            this._number = value;
        }

        #region Implicit Operator WebEziInteger

        public static implicit operator SInteger(string value)
        {
            if(String.IsNullOrEmpty(value))
            {
                return new SInteger(null);
            }
            else
            {
                int tempNumber;
                if(int.TryParse(value, out tempNumber))
                {
                    return new SInteger(tempNumber);
                }
                else
                {
                    throw new DefinedDataException("The source value is" + value);
                }
            }
        }

        public static implicit operator SInteger(int? value)
        {
            return new SInteger(value);
        }

        public static implicit operator SInteger(short? value)
        {
            return new SInteger(value);
        }

        public static implicit operator SInteger(byte? value)
        {
            return new SInteger(value);
        }

        #endregion

        #region Implicit Operator Other

        public static implicit operator string(SInteger value)
        {
            return value._number.ToString();
        }

        public static implicit operator int(SInteger value)
        {
            if (value._number.HasValue)
            {
                int tempValue;
                if (int.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to int.");
                }
            }
            else
            {
                return 0;
            }
        }

        public static implicit operator int?(SInteger value)
        {
            return value._number;
        }

        public static implicit operator short(SInteger value)
        {
            if (value._number.HasValue)
            {
                short tempValue;
                if(short.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to short.");
                }
            }
            else
            {
                return 0;
            }
        }

        public static implicit operator short?(SInteger value)
        {
            if(value._number.HasValue)
            {
                short tempValue;
                if (short.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to short.");
                }
            }
            else
            {
                return null;
            }
        }

        public static implicit operator byte(SInteger value)
        {
            if (value._number.HasValue)
            {
                byte tempValue;
                if (byte.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to byte.");
                }
            }
            else
            {
                return 0;
            }
        }

        public static implicit operator byte?(SInteger value)
        {
            if (value._number.HasValue)
            {
                byte tempValue;
                if (byte.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to byte.");
                }
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region Implicit Operator

        public static bool operator ==(SInteger x, SInteger y)
        {
            return x._number == y._number;
        }

        public static bool operator !=(SInteger x, SInteger y)
        {
            return x._number != y._number;
        }

        #endregion

        public override string ToString()
        {
            return _number.ToString();
        }

        /// <summary>
        /// Return the value is null
        /// </summary>
        /// <returns>The value is null</returns>
        public bool IsNull()
        {
            return !_number.HasValue;
        }

        #region IComparable<WebEziInteger> Members

        public int CompareTo(SInteger other)
        {
            if (_number.HasValue)
            {
                return _number.Value.CompareTo(other._number);
            }
            else if (!other._number.HasValue)
            {
                return 0;
            }
            else
            {
                return -1;
            }
        }

        #endregion

        public bool Equals(SInteger obj)
        {
            return obj._number.Equals(_number);
        }

        public override bool Equals(object obj)
        {
            if (obj.GetType() != typeof (SInteger)) return false;
            return Equals((SInteger) obj);
        }

        public override int GetHashCode()
        {
            return (_number.HasValue ? _number.Value : 0);
        }
    }
}
